package server;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.Socket;
import java.util.concurrent.BrokenBarrierException;

import smash_tris.*;

/**
 * Klasa reprezentuje połączenie pomiędzy klientem a serwerem.
 * 
 * @author Maciej Graszek
 * @author Pawel Rychly
 * 
 */
public class Connection implements Runnable, Serializable {

	private SmashTrisManager manager = null;
	private Socket clientSocket = null;
	private ObjectInputStream in = null;
	private ObjectOutputStream out = null;
	private ObjectOutputStream broadcastOut = null;
	private boolean isThreadRunning = true;
	private Player player = null;
	private boolean waitingMode = false;
	private Room currentGameRoom = null;
	private boolean gameRunning = false;

	public Connection(Socket clientSocket, ObjectOutputStream broadcastOut,
			SmashTrisManager manager) {
		this.broadcastOut = broadcastOut;
		this.clientSocket = clientSocket;
		this.manager = manager;
		System.out.println("1");
		Thread t = new Thread(this);
		t.start();
	
	}

	@Override
	public void run() {

		try {
			this.out = new ObjectOutputStream(new BufferedOutputStream(
					clientSocket.getOutputStream()));
			this.out.flush();

			
			this.in = new ObjectInputStream(new BufferedInputStream(
					clientSocket.getInputStream()));

			while (isThreadRunning) {
				DataPacket userInput;
				try {
					while ((isThreadRunning)
							&& (userInput = (DataPacket) in.readObject()) != null) {

						switch (userInput.getTypeOfInformation()) {
						case SET_START:
							System.out.println("Set start.");
							manager.setStart(currentGameRoom);
							manager.notifyPlayerInRoomCommunication(currentGameRoom);
							out.reset();
							break;
						case SET_READY:
							System.out.println("Set ready");
							Room room = (Room) userInput.getData();
							Room r1 = null;

							r1 = manager.getRoom(room);
							Integer response = manager.setReady(r1, player);
							out.writeObject(new DataPacket(
									TypeOfDataPacket.RESPONSE_OK, response));
							out.flush();
							if (response == 1) {
								currentGameRoom = r1;
								waitingMode = true;
							} else if (response == 2) {
								currentGameRoom = r1;
								manager.broadcastToPlayers(r1.getPlayers(),
										TypeOfDataPacket.START_GAME, null);
								manager.joinGameThread(r1);
							} else {
								currentGameRoom = null;
								waitingMode = false;
							}

							break;
						case JOIN_TO_ROOM:
							System.out.println("Add player to room.");
							Room rClient = (Room) userInput.getData();
							Room r = manager.getRoom(rClient);
							if (r != null) {
								System.out
										.println("-------JOIN TO ROOM--------------");
								System.out.println(r.getNumPlay());
								System.out.println(r.getPlayers().size());
								for (Player p : r.getPlayers()) {
									System.out.println(p.getNick());
								}
								System.out.println("---------------------");
								r.addPlayer(this.player);
								
								System.out
										.println("-------AFTER THIS ACTION-------------");
								System.out.println(r.getNumPlay());
								System.out.println(r.getPlayers().size());
								for (Player p : r.getPlayers()) {
									System.out.println(p.getNick());
								}
								System.out.println("---------------------");
								manager.joinTogameRoomCommunication(r, in, out,
										player);
								currentGameRoom = r;
								out.writeObject(new DataPacket(
										TypeOfDataPacket.RESPONSE_OK, null));
								out.flush();
								
						
							} else {
								System.out.println("Nie znaleziono pokoju.");
							}
							break;
						case ADD_PLAYER:
							System.out.println("Add player.");
							Object nick = userInput.getData();
							Player player = new Player(nick.toString());

							System.out.println(player.getNick());
							this.manager.addOutputStreamToBroadcast(player,
									broadcastOut);
							this.manager.addNewPlayer(player);
							this.manager.linkConnectionToPlayer(player, this);
							this.player = player;
							this.out.writeObject(new DataPacket(
									TypeOfDataPacket.RESPONSE_OK, player));
							this.out.flush();
							break;
						case GET_LIST_OF_PLAYERS:
							System.out.println("Get list of players.");
							this.out.writeObject(new DataPacket(
									TypeOfDataPacket.RESPONSE_OK, manager
											.getPlayersList()));
							this.out.flush();
							break;
						case GET_LIST_OF_ROOMS:
							System.out.println("Get list of rooms.");
							this.out.writeObject(new DataPacket(
									TypeOfDataPacket.RESPONSE_OK, manager
											.getRoomList()));
							this.out.flush();
							break;
						case GET_ROOM:
							System.out.println("Get room");
							Room rom = (Room) userInput.getData();
							Room rum = manager.getRoom(rom);

							if (rum != null)
								this.out.writeObject(new DataPacket(
										TypeOfDataPacket.RESPONSE_OK, rum));
							else
								this.out.writeObject(new DataPacket(
										TypeOfDataPacket.RESPONSE_ERROR, rum));
								this.out.flush();
							break;	
						case ADD_ROOM:
							System.out.println("Add room");
							Object nick2 = userInput.getData();
							Room room2 = new Room(this.player, nick2.toString());
							//Room room2 = (Room) userInput.getData();
							//Room room2 = new Room(player, name);
							room2.addPlayer(this.player);
							if (this.manager.addNewRoom(room2)) {
								System.out.println("tworzenie pokoju gry");
								manager.createGameRoomCommunication(room2, in,
										out);
								System.out.println("Zakończenie tworzenia pokoju gry.");
								this.out.writeObject(new DataPacket(
										TypeOfDataPacket.RESPONSE_OK, room2));
								this.out.flush();
								System.out.println("OK_");

							} else {
								this.out.writeObject(new DataPacket(
										TypeOfDataPacket.RESPONSE_ERROR, null));
								this.out.flush();
							}
							currentGameRoom = room2;
							break;
						case REMOVE_ROOM:
							System.out.println("Remove room");
							Room room3 = (Room) userInput.getData();
							if (this.manager.removeRoom(room3)) {
								this.out.writeObject(new DataPacket(
										TypeOfDataPacket.RESPONSE_OK, manager
												.getRoomList()));
								this.out.flush();
							} else {
								this.out.writeObject(new DataPacket(
										TypeOfDataPacket.RESPONSE_ERROR, null));
								this.out.flush();
							}
							// TODO implementacja polecenia.
							break;
						case REMOVE_PLAYER:
							System.out.println("Remove player");
							Player pl = (Player) userInput.getData();
							this.manager.removePlayer(pl);
							this.out.writeObject(new DataPacket(
									TypeOfDataPacket.RESPONSE_OK, manager
											.getRoomList()));
							this.out.flush();
							isThreadRunning = false;
							break;
						case EXIT_FROM_ROOM:
							System.out.println("Exit");

							this.manager.removeFromGameRoomCommunication(
									manager.getRoom(currentGameRoom), this.player);
							break;
						}
						

					}

				} catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					System.out.println("Przerwany potok");

					// e.printStackTrace();
				}

			}

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e2) {
			System.out.println("Exception");
			e2.printStackTrace();
		}
		

	}

}
